unit CEOTypesUnit;

{$mode objfpc}{$H+}

{
The MIT License (MIT)

Copyright (c) 2012 Gustavo Carreno <guscarreno@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
}

interface

uses
  Classes, SysUtils, Graphics, FileUtil, IniFiles, HTTPSend;

type
  { Online Update container }

    { TCEOOnlineUpdate }

    TCEOOnlineUpdate = class
    private
      FIniLocal, FIniRemote: TIniFile;
      FHTTP: THTTPSend;

      procedure CopyLocalToRemote;
      procedure CopyRemoteToLocal;
    public
      constructor Create;
      destructor Destroy; override;

      property LocalFile: TIniFile read FIniLocal;
      property RemoteFile: TIniFile read FIniRemote;
    end;

{ Settings container }

  { TCEOSettings }

  TVisibleTabsArray = Array [0..9] of Boolean;

  TCEOSettings = class
  private
    FIniFile: TIniFile;
    FTabsPosition: Integer;
    FTabsShowCloseButton: Boolean;
    FVisibleTabs: TVisibleTabsArray;
    FLanguage: Integer;
    FUpdateInterval: Integer;

    procedure CheckSettings;
  public
    constructor Create;

    procedure LoadSettings;
    procedure SaveSettings;

    property TabsPosition: Integer read FTabsPosition write FTabsPosition default 0;
    property VisibleTabs: TVisibleTabsArray read FVisibleTabs write FVisibleTabs;
    property Language: Integer read FLanguage write FLanguage default 0;
    property UpdateInterval: Integer read FUpdateInterval write FUpdateInterval default 0;
    property ShowCloseButtons: Boolean read FTabsShowCloseButton write FTabsShowCloseButton default False;
  end;

{ Base class }
  { TCEOObject }

  TCEOObject = class
  private
    FName: String;
    FPictureResName: String;
  public
    property Name: String read FName;
    property PictureResName: String read FPictureResName;
  end;

{ Base class for storage buildings }
  { TStorageBuilding }

  TStorageBuilding = class(TCEOObject)
  private
    FIsMayor: Boolean;
  end;

{ ==  Storage Buildings == }
  { TMayorsHouse }

  TMayorsHouse = class(TStorageBuilding)
  private
    {Private declarations}
  public
    constructor Create;
  end;

{ TWareHouse }

  TWareHouse = class(TStorageBuilding)
  private
    {Private declarations}
  public
    constructor Create;
  end;
{ ==  Storage Buildings == }

{ Base class for Settlers and Bandits }

  { TDamage }

  TDamage = array [1..2] of Integer;

  { TAttackInitiative }

  TAttackInitiative = (aiFirstAttack, aiNormalAttack, aiSlowAttack);

  { TAttackSkill }

  TAttackSkill = (asAccuracyTower, asFirstStrike, asTrample, asAttackWeakest,
                  asCautious);

  { TAttackSkills }

  TAttackSkills = set of TAttackSkill;

  { TSettler }

  TSettler = class(TCEOObject)
  private
    FThumbnailResName: String;
    FDesc: String;
    FHitPoints: Integer;
    FDamage: TDamage;
    FAccuracy: Double;
    FSkills: TAttackSkills;
    FInitiative: TAttackInitiative;
    FQuantity: Integer;
  public
    property Thumbnail: String read FThumbnailResName;
    property HitPoints: Integer read FHitPoints;
    property Damage: TDamage read FDamage;
    property Accuracy: Double read FAccuracy;
    property Skills: TAttackSkills read FSkills;
    property Initiative: TAttackInitiative read FInitiative;
    Property Quantity: Integer read FQuantity write FQuantity;
  end;

{ ==  Settler Units == }
  { TSettlerRecruit }

  TSettlerRecruit = class(TSettler)
  public
    constructor Create;
  end;

  { TSettlerBowman }

  TSettlerBowman = class(TSettler)
  private
    FHasTower: Boolean;
  public
    constructor Create;

    property HasTower: Boolean read FHasTower write FHasTower;
  end;

  { TSettlerMilitia }

  TSettlerMilitia = class(TSettler)
  public
    constructor Create;
  end;

  { TSettlerCavalry }

  TSettlerCavalry = class(TSettler)
  public
    constructor Create;
  end;

  { TSettlerLongbowman }

  TSettlerLongbowman = class(TSettler)
  private
    FHasTower: Boolean;
  public
    constructor Create;

    property HasTower: Boolean read FHasTower write FHasTower;
  end;

  { TSettlerSoldier }

  TSettlerSoldier = class(TSettler)
  public
    constructor Create;
  end;
{ ==  Settler Units == }

{ ==  Bandit Units == }
  { TBanditScavenger }

  TBanditScavenger = class(TSettler)
  public
    constructor Create;
  end;

  { TBanditStoneThrower }

  TBanditStoneThrower = class(TSettler)
  private
    FHasTower: Boolean;
  public
    constructor Create;

    property HasTower: Boolean read FHasTower write FHasTower;
  end;
{ ==  Bandit Units == }

var
  CEOSettings: TCEOSettings;
  CEOOnlineUpdate: TCEOOnlineUpdate;

implementation

uses
  CEOResourcesUnit;

{ TCEOOnlineUpdate }

procedure TCEOOnlineUpdate.CopyLocalToRemote;
var
  Sections, Idents: TStringList;
  SectionIndex, IdentIndex: Integer;
begin
  Sections:= TStringList.Create;
  Idents:= TStringList.Create;
  try
    FIniLocal.ReadSections(Sections);
    for SectionIndex:= 0 to Sections.Count - 1 do
    begin
      FIniLocal.ReadSection(Sections[SectionIndex], Idents);
      for IdentIndex:=0 to Idents.Count - 1 do
      begin
        FIniRemote.WriteString(Sections[SectionIndex], Idents[IdentIndex],
          FIniLocal.ReadString(Sections[SectionIndex], Idents[IdentIndex], ''));
      end;
    end;
  finally
    Sections.Free;
    Idents.Free;
  end;
end;

procedure TCEOOnlineUpdate.CopyRemoteToLocal;
var
  Sections, Idents: TStringList;
  SectionIndex, IdentIndex: Integer;
begin
  Sections:= TStringList.Create;
  Idents:= TStringList.Create;
  try
    FIniRemote.ReadSections(Sections);
    for SectionIndex:= 0 to Sections.Count - 1 do
    begin
      FIniRemote.ReadSection(Sections[SectionIndex], Idents);
      for IdentIndex:=0 to Idents.Count - 1 do
      begin
        FIniLocal.WriteString(Sections[SectionIndex], Idents[IdentIndex],
          FIniRemote.ReadString(Sections[SectionIndex], Idents[IdentIndex], ''));
      end;
    end;
  finally
    Sections.Free;
    Idents.Free;
  end;
end;

constructor TCEOOnlineUpdate.Create;
begin
  inherited Create;

  if not DirectoryExists(envAppContentDir) then
  begin
    CreateDir(envAppContentDir);
  end;
  FHTTP:= THTTPSend.Create;
  try
    if FHTTP.HTTPMethod('GET', cContentVersionURL) then
    begin
      if FHTTP.ResultCode = 200 then
      begin
        FIniRemote:= TIniFile.Create(FHTTP.Document);
      end
      else
      begin
        FIniRemote:= TIniFile.Create(TMemoryStream.Create);
        CopyLocalToRemote;
      end;
    end;
  finally
    FHTTP.Free;
  end;
  if not FileExists(envAppOnlineUpdateFile) then
  begin
    FIniLocal:= TIniFile.Create(envAppOnlineUpdateFile);
    CopyRemoteToLocal;
  end
  else
  begin
    FIniLocal:= TIniFile.Create(envAppOnlineUpdateFile);
  end;
end;

destructor TCEOOnlineUpdate.Destroy;
begin
  if Assigned(FIniLocal) then
    FIniLocal.Free;
  if Assigned(FIniRemote) then
    FIniRemote.Free;

  inherited Destroy;
end;

{ TCEOSettings }

constructor TCEOSettings.Create;
var
  Index: Integer;
begin
  inherited Create;
  for Index:= 0 to 9 do
    FVisibleTabs[Index]:= True;
  LoadSettings;
end;

procedure TCEOSettings.CheckSettings;
var
  Index: Integer;
begin
  if not DirectoryExists(envAppConfigDir) then
  begin
    CreateDir(envAppConfigDir);
  end;
  if not FileExists(envAppConfigFile) then
  begin
    FIniFile:= TIniFile.Create(envAppConfigFile);
    try
      FIniFile.WriteInteger('Main', 'TabPosition', 0);
      FIniFile.WriteBool('Main', 'TabShowClose', False);
      for Index:= 0 to 9 do
      begin
        FIniFile.WriteBool('Main', 'Tab' + IntToStr(Index), FVisibleTabs[Index]);
      end;
      FIniFile.WriteInteger('Main', 'Language', 0);
      FIniFile.WriteInteger('Main', 'UpdateInterval', 0);
    finally
      FIniFile.Free;
    end;
  end;
end;

procedure TCEOSettings.LoadSettings;
var
  Index: Integer;
begin
  CheckSettings;
  FIniFile:= TIniFile.Create(envAppConfigFile);
  try
    FTabsPosition:= FIniFile.ReadInteger('Main', 'TabPosition', 0);
    FTabsShowCloseButton:= FIniFile.ReadBool('Main', 'TabShowClose', False);
    for Index:= 0 to 9 do
    begin
      FVisibleTabs[Index]:= FIniFile.ReadBool('Main', 'Tab' + IntToStr(Index), True);
    end;
    FLanguage:= FIniFile.ReadInteger('Main', 'Language', 0);
    FUpdateInterval:= FIniFile.ReadInteger('Main', 'UpdateInterval', 0);
  finally
    FIniFile.Free;
  end;
end;

procedure TCEOSettings.SaveSettings;
var
  Index: Integer;
begin
  CheckSettings;
  FIniFile:= TIniFile.Create(envAppConfigFile);
  try
    FIniFile.WriteInteger('Main', 'TabPosition', FTabsPosition);
    FIniFile.WriteBool('Main', 'TabShowClose', FTabsShowCloseButton);
    for Index:= 0 to 9 do
    begin
      FIniFile.WriteBool('Main', 'Tab' + IntToStr(Index), FVisibleTabs[Index]);
    end;
    FIniFile.WriteInteger('Main', 'Language', FLanguage);
    FIniFile.WriteInteger('Main', 'UpdateInterval', FUpdateInterval);
  finally
    FIniFile.Free;
  end;
end;

{== Settler Units ==}
{ TSettlerRecruit }

constructor TSettlerRecruit.Create;
begin
  inherited;
  FPictureResName:= 'icon_settler_recruit';

  FThumbnailResName:= 'small_icon_settler_recruit';

  FName       := 'Recruit';
  FHitPoints  := 40;
  FDamage[1]  := 15;
  FDamage[2]  := 30;
  FAccuracy   := 0.8;
  FSkills     := [];
  FInitiative := aiNormalAttack;
  FDesc       := 'Melee fighter.'+LineEnding+
                 'Low hitpoints.'+LineEnding+
                 'Low damage.'+LineEnding+LineEnding+
                 'Hitpoints: '+IntToStr(FHitPoints)+LineEnding+
                 'Damage: '+IntToStr(FDamage[1])+'-'+IntToStr(FDamage[2])+LineEnding+
                 'Accuracy: '+FloatToStr(FAccuracy*100)+'%'+LineEnding+
                 'Initiative: Normal';
  FQuantity   := 0;
end;

{ TSettlerBowman }

constructor TSettlerBowman.Create;
begin
  inherited;
  FPictureResName:= 'icon_settler_bowman';

  FThumbnailResName:= 'small_icon_settler_bowman';

  FName       := 'Bowman';
  FHitPoints  := 10;
  FDamage[1]  := 20;
  FDamage[2]  := 40;
  FAccuracy   := 0.8;
  FSkills     := [asAccuracyTower, asCautious];
  FInitiative := aiNormalAttack;
  FDesc       := 'Basic ranged unit.'+LineEnding+
                 'Very low hitpoints.'+LineEnding+
                 'Low damage.'+LineEnding+
                 'Skill: Cautious'+LineEnding+LineEnding+
                 'Cautious: Unit will only be attacked if all melee troops of this army are defeated.'+LineEnding+LineEnding+
                 'Hitpoints: '+IntToStr(FHitPoints)+LineEnding+
                 'Damage: '+IntToStr(FDamage[1])+'-'+IntToStr(FDamage[2])+LineEnding+
                 'Accuracy: '+FloatToStr(FAccuracy*100)+'%'+LineEnding+
                 'Initiative: Normal'+LineEnding+LineEnding+
                 'Skills:'+LineEnding+
                 '- Bonus AC in tower.';
  FHasTower   := False;
  FQuantity   := 0;
end;

{ TSettlerMilitia }

constructor TSettlerMilitia.Create;
begin
  inherited;
  FPictureResName:= 'icon_settler_militia';

  FThumbnailResName:= 'small_icon_settler_militia';

  FName       := 'Militia';
  FHitPoints  := 60;
  FDamage[1]  := 20;
  FDamage[2]  := 40;
  FAccuracy   := 0.8;
  FSkills     := [];
  FInitiative := aiNormalAttack;
  FDesc       := 'Experienced melee fighter.'+LineEnding+
                 'Medium hitpoints.'+LineEnding+
                 'Low damage.'+LineEnding+LineEnding+
                 'Hitpoints: '+IntToStr(FHitPoints)+LineEnding+
                 'Damage: '+IntToStr(FDamage[1])+'-'+IntToStr(FDamage[2])+LineEnding+
                 'Accuracy: '+FloatToStr(FAccuracy*100)+'%'+LineEnding+
                 'Initiative: Normal';
  FQuantity   := 0;
end;

{ TSettlerCavalry }

constructor TSettlerCavalry.Create;
begin
  inherited;
  FPictureResName:= 'icon_settler_cavalry';

  FThumbnailResName:= 'small_icon_settler_cavalry';

  FName       := 'Cavalry';
  FHitPoints  := 5;
  FDamage[1]  := 5;
  FDamage[2]  := 10;
  FAccuracy   := 0.8;
  FSkills     := [asFirstStrike, asTrample, asAttackWeakest];
  FInitiative := aiFirstAttack;
  FDesc       := 'Fast mounted strike force.'+LineEnding+
                 'Very low hitpoints.'+LineEnding+
                 'Medium damage.'+LineEnding+
                 'Skill: First strike'+LineEnding+
                 'Skill: Trample'+LineEnding+LineEnding+
                 'First strike: Attack before normal and slow units can strike back.'+LineEnding+LineEnding+
                 'Trample: Attack units with lowest maximum hitpoints first.'+LineEnding+LineEnding+
                 'Hitpoints: '+IntToStr(FHitPoints)+LineEnding+
                 'Damage: '+IntToStr(FDamage[1])+'-'+IntToStr(FDamage[2])+LineEnding+
                 'Accuracy: '+FloatToStr(FAccuracy*100)+'%'+LineEnding+
                 'Initiative: First strike'+LineEnding+LineEnding+
                 'Skills:'+LineEnding+
                 '- Attack weakest target';
  FQuantity   := 0;
end;

{ TSettlerLongbowman }

constructor TSettlerLongbowman.Create;
begin
  inherited;
  FPictureResName:= 'icon_settler_longbowman';

  FThumbnailResName:= 'small_icon_settler_longbowman';

  FName       := 'Longbowman';
  FHitPoints  := 10;
  FDamage[1]  := 30;
  FDamage[2]  := 60;
  FAccuracy   := 0.8;
  FSkills     := [asAccuracyTower, asCautious];
  FInitiative := aiNormalAttack;
  FHasTower   := False;
  FDesc       := 'Experienced ranged unit.'+LineEnding+
                 'Very low hitpoints.'+LineEnding+
                 'Medium damage.'+LineEnding+
                 'Skill: Cautious'+LineEnding+LineEnding+
                 'Cautious: Unit will only be attacked if all melee troops of this army are defeated.'+LineEnding+LineEnding+
                 'Hitpoints: '+IntToStr(FHitPoints)+LineEnding+
                 'Damage: '+IntToStr(FDamage[1])+'-'+IntToStr(FDamage[2])+LineEnding+
                 'Accuracy: '+FloatToStr(FAccuracy*100)+'%'+LineEnding+
                 'Initiative: Normal'+LineEnding+LineEnding+
                 'Skills:'+LineEnding+
                 '- Bonus AC in tower.';
  FQuantity   := 0;
end;

{ TSettlerSoldier }

constructor TSettlerSoldier.Create;
begin
  inherited;
  FPictureResName:= 'icon_settler_soldier';

  FThumbnailResName:= 'small_icon_settler_soldier';

  FName       := 'Soldier';
  FHitPoints  := 90;
  FDamage[1]  := 20;
  FDamage[2]  := 40;
  FAccuracy   := 0.85;
  FSkills     := [];
  FInitiative := aiNormalAttack;
  FDesc       := 'Melee veteran.'+LineEnding+
                 'High hitpoints.'+LineEnding+
                 'Low damage.'+LineEnding+LineEnding+
                 'Hitpoints: '+IntToStr(FHitPoints)+LineEnding+
                 'Damage: '+IntToStr(FDamage[1])+'-'+IntToStr(FDamage[2])+LineEnding+
                 'Accuracy: '+FloatToStr(FAccuracy*100)+'%'+LineEnding+
                 'Initiative: Normal';
  FQuantity   := 0;
end;
{== Settler Units ==}

{== Bandit Units ==}
{ TBanditStoneThrower }

constructor TBanditStoneThrower.Create;
begin
  inherited;
  FPictureResName:= 'icon_bandit_recruit';

  FThumbnailResName:= 'small_icon_bandit_recruit';

  FHitPoints:= 0;
  //FDamage:=    0;
end;

{ TBanditScavenger }

constructor TBanditScavenger.Create;
begin
  inherited;
  FPictureResName:= 'icon_bandit_bowman';

  FThumbnailResName:= 'small_icon_bandit_bowman';

  FHitPoints:= 0;
  //FDamage:=    0;
end;
{== Bandit Units ==}

{ TWareHouse }

constructor TWareHouse.Create;
begin
  inherited;
  FPictureResName:= 'icon_warehouse';
  FIsMayor:= False;
end;

{ TMayorsHouse }

constructor TMayorsHouse.Create;
begin
  inherited;
  FPictureResName:= 'icon_mayorhouse';
  FIsMayor:= True;
end;

initialization

CEOSettings:= TCEOSettings.Create;
CEOOnlineUpdate:= TCEOOnlineUpdate.Create;

finalization

CEOOnlineUpdate.Free;
CEOSettings.Free;

end.

